#include <windows.h>
#include <iostream>
#include <stdio.h>
using namespace std;
// 创建传递过来的进程的克隆过程并赋于其ID值
void StartClone(int nCloneID)
{
    // 获取用于当前可执行文件的文件名和路径名
    TCHAR szFilename[MAX_PATH];
    GetModuleFileName(NULL, szFilename, MAX_PATH);
    // 格式化用于子进程的命令行并通知其EXE文件名和克隆ID
    TCHAR szCmdLine[MAX_PATH];
#ifdef UNICODE
    swprintf_s(szCmdLine, MAX_PATH, L"\"%ls\" %d", szFilename, nCloneID);
#else
    sprintf_s(szCmdLine, MAX_PATH, "\"%s\" %d", szFilename, nCloneID);
#endif
    // 用于子进程的STARTUPINFO结构
    STARTUPINFO si;
    ZeroMemory(reinterpret_cast <void*> (&si), sizeof(si));
    si.cb = sizeof(si);
    // 返回的用于子进程的进程信息
    PROCESS_INFORMATION pi;
    // 利用同样的可执行文件和命令行创建进程，并赋于其子进程的性质
    if (!CreateProcess(
        szFilename,    // 产生这个EXE的应用程序的名称
        szCmdLine,    // 命令行
        NULL,        // 缺省的进程安全性
        NULL,       // 缺省的线程安全性
        FALSE,     // 不继承句柄
        0,    // 使用新的控制台
        NULL,     // 新的环境
        NULL,    // 当前目录
        &si,     // 启动信息
        &pi))  // 返回的进程信息
    {
        cerr << "CreateProcess failed (" << GetLastError() << ").\n";
        return;
    }
    // 对子进程释放引用
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}
int main(int argc, char* argv[])
{
    // 确定进程在列表中的位置
    int nClone = 0;
    if (argc > 1)
    {
        sscanf_s(argv[1], "%d", &nClone, (unsigned int)sizeof(nClone));
    }
    // 显示进程位置
    cout << "Process ID: " << GetCurrentProcessId() << ", Clone ID: " << nClone << endl;
    cout << endl;
    Sleep(4000);
    // 检查是否有创建子进程的需要
    const int c_nCloneMax = 5;
    if (nClone < c_nCloneMax)
    {
        StartClone(++nClone);
    }
    // 在终止之前暂停一下
    Sleep(5000);
    return 0;
}